package com.pan.kang.controller;

import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey;
import com.alibaba.druid.sql.ast.statement.SQLTableElement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlCreateTableParser;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.pan.kang.builder.DataBuilder;
import com.pan.kang.builder.ExcelBuilder;
import com.pan.kang.builder.JavaCodeBuilder;
import com.pan.kang.builder.SqlBuilder;
import com.pan.kang.constant.MockTypeEnum;
import com.pan.kang.entity.TableSchemaEntity;
import com.pan.kang.model.Request;
import com.pan.kang.model.TableSchema;
import com.pan.kang.model.TableSchemaExcel;
import com.pan.kang.service.TableSchemaService;
import com.pan.kang.transfer.TableSchemaTransfer;
import com.pan.kang.util.SQLDialectUtil;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@RestController
@RequestMapping("/api")
public class SqlController {

    @Autowired
    private TableSchemaService tableSchemaService;

    @Autowired
    private TableSchemaTransfer tableSchemaTransfer;

    @Autowired
    private JavaCodeBuilder javaCodeBuilder;


    /**
     * 将创建表语句构造模型
     */
    @PostMapping("/save/model/by/sql")
    public TableSchema saveModelBySql(@RequestBody Request.SqlRequest request) {

        // 解析 SQL
        MySqlCreateTableParser parser = new MySqlCreateTableParser(request.getSql());
        SQLCreateTableStatement sqlCreateTableStatement = parser.parseCreateTable();
        TableSchema model = new TableSchema();
        model.setDbName(sqlCreateTableStatement.getSchema());
        model.setTableName(SQLDialectUtil.parseTableName(sqlCreateTableStatement.getTableName()));
        String tableComment = null;
        if (sqlCreateTableStatement.getComment() != null) {
            tableComment = sqlCreateTableStatement.getComment().toString();
            if (tableComment.length() > 2) {
                tableComment = tableComment.substring(1, tableComment.length() - 1);
            }
        }
        model.setTableComment(tableComment);
        List<TableSchema.Field> fieldList = new LinkedList<>();
        // 解析列
        for (SQLTableElement sqlTableElement : sqlCreateTableStatement.getTableElementList()) {
            // 主键约束
            if (sqlTableElement instanceof SQLPrimaryKey) {
                SQLPrimaryKey sqlPrimaryKey = (SQLPrimaryKey) sqlTableElement;
                String primaryFieldName = SQLDialectUtil.parseFieldName(sqlPrimaryKey.getColumns().get(0).toString());
                fieldList.forEach(field -> {
                    if (field.getFieldName().equals(primaryFieldName)) {
                        field.setPrimaryKey(true);
                    }
                });
            } else if (sqlTableElement instanceof SQLColumnDefinition) {
                // 列
                SQLColumnDefinition columnDefinition = (SQLColumnDefinition) sqlTableElement;
                TableSchema.Field field = new TableSchema.Field();
                field.setFieldName(SQLDialectUtil.parseFieldName(columnDefinition.getNameAsString()));
                field.setFieldType(columnDefinition.getDataType().toString());
                String defaultValue = null;
                if (columnDefinition.getDefaultExpr() != null) {
                    defaultValue = columnDefinition.getDefaultExpr().toString();
                }
                field.setDefaultValue(defaultValue);
                field.setNotNull(columnDefinition.containsNotNullConstaint());
                String comment = null;
                if (columnDefinition.getComment() != null) {
                    comment = columnDefinition.getComment().toString();
                    if (comment.length() > 2) {
                        comment = comment.substring(1, comment.length() - 1);
                    }
                }
                field.setComment(comment);
                field.setPrimaryKey(columnDefinition.isPrimaryKey());
                field.setAutoIncrement(columnDefinition.isAutoIncrement());
                String onUpdate = null;
                if (columnDefinition.getOnUpdate() != null) {
                    onUpdate = columnDefinition.getOnUpdate().toString();
                }
                field.setOnUpdate(onUpdate);
                field.setMockType(MockTypeEnum.NONE.getValue());
                fieldList.add(field);
            }
        }
        model.setFieldList(fieldList);
        CompletableFuture.runAsync(() -> tableSchemaService.saveTableSchemaModel(model));
        return model;
    }

    /**
     * 根据模型构造建表语句
     */
    @PostMapping("/get/create/sql/by/model")
    public String gerCreateSqlByModel(@RequestBody Request.TableSchemaRequest request) {
        TableSchema model = tableSchemaTransfer.requestToModel(request);
        return SqlBuilder.buildCreateTableSql(model);
    }

    /**
     * 根据模型构造插入语句
     */
    @PostMapping("/get/insert/sql/by/model")
    public String getInsertSqlByModel(@RequestBody Request.TableSchemaRequest request) {
        TableSchema model = tableSchemaTransfer.requestToModel(request);
        return SqlBuilder.buildInsertSql(model, DataBuilder.builderData(model, model.getMockNum()));
    }

    /**
     * 根据表名构造模型
     */
    @PostMapping("/get/model/by/name")
    public TableSchema getModelByTableName(@RequestBody Request.tableNameRequest request) {
        List<TableSchemaEntity> list =
                tableSchemaService.list(new LambdaQueryWrapper<TableSchemaEntity>()
                        .eq(TableSchemaEntity::getTableName, request.getTableName()));
        return tableSchemaTransfer.entityToModel(list);
    }

    /**
     * 根据模型构造JAVA类
     */
    @PostMapping("/get/java/code/by/model")
    public String getJavaCodeByModel(@RequestBody Request.TableSchemaRequest request)
            throws TemplateException, IOException {
        TableSchema model = tableSchemaTransfer.requestToModel(request);
        return javaCodeBuilder.buildJavaEntityCode(model, "java_class.ftl");
    }


    /**
     * 根据表名构造JAVA类
     */
    @PostMapping("/get/java/code/by/name")
    public String getJavaCodeByTableName(@RequestBody Request.tableNameRequest request)
            throws TemplateException, IOException {
        TableSchema model = getModelByTableName(request);
        return javaCodeBuilder.buildJavaEntityCode(model, "java_class.ftl");
    }

    /**
     * 根据模型模拟数据
     */
    @PostMapping("/get/model/data")
    public List<Map<String, Object>> getModeData(@RequestBody Request.TableSchemaRequest request) {
        TableSchema model = tableSchemaTransfer.requestToModel(request);
        return DataBuilder.builderData(model, model.getMockNum());
    }

    /**
     * Excel 导入建模
     */
    @PostMapping("/get/model/by/excel")
    public TableSchema getModelByExcel(MultipartFile file) throws IOException {
        List<TableSchemaExcel> list = ExcelBuilder.buildFromExcel(file);
        TableSchema model = tableSchemaTransfer.excelToModel(list);
        CompletableFuture.runAsync(() -> tableSchemaService.saveTableSchemaModel(model));
        return model;
    }

    /**
     * Excel 导入构建创建 SQL
     */
    @PostMapping("get/create/sql/by/excel")
    public String getCreateSqlByExcel(MultipartFile file) throws IOException {
        List<TableSchemaExcel> list = ExcelBuilder.buildFromExcel(file);
        TableSchema model = tableSchemaTransfer.excelToModel(list);
        return SqlBuilder.buildCreateTableSql(model);
    }


    /**
     * Excel 导入构建 JAVA 实体类
     */
    @PostMapping("/get/java/code/by/excel")
    public String getJavaCodeByExcel(MultipartFile file) throws IOException, TemplateException {
        List<TableSchemaExcel> list = ExcelBuilder.buildFromExcel(file);
        TableSchema model = tableSchemaTransfer.excelToModel(list);
        return javaCodeBuilder.buildJavaEntityCode(model, "java_class.ftl");
    }

    /**
     * Excel 导入构建 JAVA 实体实现类
     */
    @PostMapping("/get/java/object/by/excel")
    public String getJavaObjectByExcel(MultipartFile file) throws IOException, TemplateException {
        List<TableSchemaExcel> list = ExcelBuilder.buildFromExcel(file);
        TableSchema model = tableSchemaTransfer.excelToModel(list);
        List<Map<String, Object>> dataList = DataBuilder.builderData(model, model.getMockNum());
        return javaCodeBuilder.buildJavaObjectCode(model, dataList);
    }

    /**
     * Excel 导入构建 JAVA Entity类
     */
    @PostMapping("/get/java/entity/by/excel")
    public String getJavaEntityByExcel(MultipartFile file) throws IOException, TemplateException {
        List<TableSchemaExcel> list = ExcelBuilder.buildFromExcel(file);
        TableSchema model = tableSchemaTransfer.excelToModel(list);
        return javaCodeBuilder.buildJavaEntityCode(model, "java_entity.ftl");
    }

    /**
     * Excel 导入构建 insert 语句
     */
    @PostMapping("/get/insert/sql/by/excel")
    public String getInsertSqlByExcel(MultipartFile file) throws IOException, TemplateException {
        List<TableSchemaExcel> list = ExcelBuilder.buildFromExcel(file);
        TableSchema model = tableSchemaTransfer.excelToModel(list);
        return SqlBuilder.buildInsertSql(model, DataBuilder.builderData(model, model.getMockNum()));
    }
}
